package com.vicene.gmail.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.vicene.gmail.common.to.es.SkuEsModel;
import com.vicene.gmail.common.utils.R;
import com.vicene.gmail.search.config.GmailESConfig;
import com.vicene.gmail.search.constant.EsConstant;
import com.vicene.gmail.search.feign.ProductFeignService;
import com.vicene.gmail.search.service.MailSearchService;
import com.vicene.gmail.search.vo.AttrResponseVo;
import com.vicene.gmail.search.vo.BrandVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.ParsedAggregation;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;
import com.vicene.gmail.search.vo.SearchParam;
import com.vicene.gmail.search.vo.SearchResult;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MailSearchServiceImpl implements MailSearchService {
    @Autowired
    RestHighLevelClient client;

    @Autowired
    ProductFeignService productFeignService;


    @Override
    public SearchResult search(SearchParam searchParam) {
        SearchResult result = null;
        //SearchRequest searchRequest = new SearchRequest();
        SearchRequest searchRequest = buildSearchRequest( searchParam);
        try{
            SearchResponse searchResponse = client.search(searchRequest , GmailESConfig.COMMON_OPTIONS);

            result = buildSearchResult(searchResponse , searchParam);
            System.out.println(result);
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    private SearchResult buildSearchResult(SearchResponse response , SearchParam param) {
        SearchResult result = new SearchResult();
        SearchHits hits = response.getHits();
        List<SkuEsModel> esModels = new ArrayList<SkuEsModel>();
        if(hits.getHits()!= null && hits.getHits().length > 0){
            //1:商品数据
            for(SearchHit hit : hits.getHits()){
                String sourceAsString = hit.getSourceAsString();
                SkuEsModel esModel = JSON.parseObject(sourceAsString, SkuEsModel.class);
                esModels.add(esModel);
            }
            result.setProducts(esModels );

            //2:分类数据
            ParsedLongTerms catalog_agg = response.getAggregations().get("catalog_agg");

            List<SearchResult.CatalogVo> catalogVos = new ArrayList<SearchResult.CatalogVo>();
            List<? extends Terms.Bucket> buckets = catalog_agg.getBuckets();
            for(Terms.Bucket bucket : buckets){
                SearchResult.CatalogVo  catalogVo = new SearchResult.CatalogVo();
                String keyAsString = bucket.getKeyAsString();
                //分类id
                catalogVo.setCatalogId(Long.parseLong(keyAsString));
                ParsedStringTerms catalog_name_agg  = bucket.getAggregations().get("catalog_name_agg");
                //分类名称
                String catalog_name = catalog_name_agg.getBuckets().get(0).getKeyAsString();
                catalogVo.setCatalogName(catalog_name);
                catalogVos.add(catalogVo);
            }
            result.setCatalogs(catalogVos);

            //3:品牌数据
            List<SearchResult.BrandVo> brandVos = new ArrayList<>();
            ParsedLongTerms brand_agg = response.getAggregations().get("brand_agg");
            for(Terms.Bucket bucket : brand_agg.getBuckets()){
                SearchResult.BrandVo  brandVo = new SearchResult.BrandVo();
                long brandId = bucket.getKeyAsNumber().longValue();
                String brandName = ((ParsedStringTerms)bucket.getAggregations().get("brand_name_agg"))
                        .getBuckets().get(0).getKeyAsString();
                String brandImg = ((ParsedStringTerms)bucket.getAggregations().get("brand_img_agg"))
                        .getBuckets().get(0).getKeyAsString();
                brandVo.setBrandId(brandId);
                brandVo.setBrandImg(brandImg);
                brandVo.setBrandName(brandName);
                brandVos.add(brandVo);
            }
            result.setBrands(brandVos);

            //4:聚合信息
            List<SearchResult.AttrVo> attrVos = new ArrayList<>();
            ParsedNested attr_agg = response.getAggregations().get("attr_agg");
            ParsedLongTerms attr_id_agg = attr_agg.getAggregations().get("attr_id_agg");
            for(Terms.Bucket bucket : attr_id_agg.getBuckets()){
                SearchResult.AttrVo  attrVo = new SearchResult.AttrVo();
                long attrId = bucket.getKeyAsNumber().longValue();
                String attrName = ((ParsedStringTerms)bucket.getAggregations().get("attr_name_agg")).
                        getBuckets().get(0).getKeyAsString();
                List<String> attr_value_agg = ((ParsedStringTerms)bucket.getAggregations().get("attr_value_agg")).
                        getBuckets().stream().map(item ->{
                    String keyAsString = ((Terms.Bucket)item).getKeyAsString();
                    return keyAsString;
                }).collect(Collectors.toList());
                attrVo.setAttrId(attrId);
                attrVo.setAttrName(attrName);
                attrVo.setAttrValue(attr_value_agg);

                attrVos.add(attrVo);
            }
            result.setAttrs(attrVos);

            //分页信息
            result.setPageNum(param.getPageNum());
            //总记录数
            long total = hits.getTotalHits().value;
            result.setTotal(total);

            //总页码
            int totalPages = (int) total % EsConstant.PRODUCT_PAGESIZE == 0 ?
                    (int)total/EsConstant.PRODUCT_PAGESIZE: ((int)total/EsConstant.PRODUCT_PAGESIZE + 1);
            result.setTotalPages(totalPages);

            List<Integer> pageNavs = new ArrayList<>();
            for(int i = 1 ;i <=totalPages; i++){
                pageNavs.add(i);
            }
            result.setPageNavs(pageNavs);

            if( param.getAttrs() != null &&  param.getAttrs().size() > 0){
                List<SearchResult.NavVo> navVos = param.getAttrs().stream().map(attr ->{
                    SearchResult.NavVo navVo = new SearchResult.NavVo();
                    String []s = attr.split("_");
                    navVo.setNavValue(s[1]);
                    R r = productFeignService.attrInfo(Long.parseLong(s[0]));
                   // result.getAttrIds().add(Long.parseLong(s[0]));
                    if(r.getCode() == 0){
                        AttrResponseVo data = (AttrResponseVo) r.getData("attr",new TypeReference<AttrResponseVo>(){});
                        navVo.setNavName(data.getAttrName());
                    }else {
                        navVo.setNavName(s[0]);
                    }
                    String encode = "";
                    String replace = replaceQueryString(param, attr,"attrs");
//
//                    String replace = param.get_queryString().replace("&attrs=" + encode , "");
                    navVo.setLink("http://search.gmail.com/list.html?"+replace);
                    return navVo;
                }).collect(Collectors.toList());

//                if(param.getBrandId()!=null && param.getBrandId().size()>0){
//                    List<SearchResult.NavVo> navs = result.getNavs();
//                    SearchResult.NavVo navVo = new SearchResult.NavVo();
//                    navVo.setNavName("品牌");
//                    R r = productFeignService.brandsInfo(param.getBrandId());
//                    if(r.getCode() ==0 ){
//                        System.out.println(r);
//                        List<BrandVo> brand = (List<BrandVo>) r.getData("brand", new TypeReference<List<BrandVo>>() {
//                        });
//                        StringBuffer sb = new StringBuffer();
//                        String replace ="";
//                        for (BrandVo brandVo : brand) {
//                            sb.append(brandVo.getName()+";");
//                            replace = replaceQueryString(param, brandVo.getBrandId()+"","brandId");
//                        }
//                        navVo.setNavValue(sb.toString());
//                        navVo.setLink("http://search.gulimall.com/list.html?"+replace);
//                    }
//                    navs.add(navVo);
//                }

                result.setNavs(navVos);

            }



            }


        return result;
    }

    private String replaceQueryString(SearchParam param, String value,String key) {
        String encode = null;

        try {
            encode = URLEncoder.encode(value,"UTF-8");
            encode = encode.replace("+","%20"); //浏览器差异
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return param.get_queryString().replace("&"+key+"="+encode,"");
    }

    private SearchRequest buildSearchRequest(SearchParam param) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //查询 模糊匹配 ， 过滤 （属性，分类，品牌，价格区间，库存）
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //模糊匹配
        if(!StringUtils.isEmpty(param.getKeyword())){
            boolQuery.must(QueryBuilders.matchQuery("skuTitle" , param.getKeyword()));
        }

        //分类
        if(param.getCatalog3Id() != null){
            boolQuery.filter(QueryBuilders.termQuery("catalogId" , param.getCatalog3Id()));
        }

        //品牌
        if(param.getBrandId() != null && param.getBrandId().size() > 0){
            boolQuery.filter(QueryBuilders.termsQuery("brandId" , param.getBrandId()));
        }

        //库存
        if(param.getHasStock() != null){
            boolQuery.filter(QueryBuilders.termQuery("hasStock" , param.getHasStock() == 1));
        }

        //价格区间
        if(!StringUtils.isEmpty(param.getSkuPrice())){
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
            String []s = param.getSkuPrice().split("_");
            if(s.length == 2){
                rangeQuery.gte(s[0]).lte(s[1]);
            }else if(s.length == 1){
                if(param.getSkuPrice().startsWith("_")){
                    rangeQuery.lte(s[0]);
                }
                if(param.getSkuPrice().endsWith("_")){
                    rangeQuery.gte(s[0]);
                }
            }
            boolQuery.filter(rangeQuery);
        }

        //规格属性查询
        if(param.getAttrs()!= null && param.getAttrs().size() > 0){
            //attrs=1_5寸:7寸&attrs=2_16G:8G
            for(String attrStr: param.getAttrs()){
                BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();

                String []s = attrStr.split("_");
                String attrId = s[0];
                String []attrValues = s[1].split(";");
                nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId" , attrId));
                nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue" , attrValues ));

                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs" , nestedBoolQuery, ScoreMode.None);
                boolQuery.filter(nestedQuery);
            }

        }

        sourceBuilder.query(boolQuery);

        //排序------------------------------》
        if(!StringUtils.isEmpty(param.getSort())){
            //sort=hostScore_asc/desc
            String sort = param.getSort();
            String []s = sort.split("_");
            SortOrder order = s[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;
            sourceBuilder.sort(s[0] , order);
        }

        //分页
        sourceBuilder.from((param.getPageNum() == null?1:param.getPageNum()-1) * EsConstant.PRODUCT_PAGESIZE);
        sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);
        //排序-----------------------------《


        //高亮------------------------------》
        if(!StringUtils.isEmpty(param.getKeyword())){
            HighlightBuilder builder = new HighlightBuilder();
            builder.field("skuTitle");
            builder.preTags("<b style='color:red'>");
            builder.postTags("</b>");
            sourceBuilder.highlighter(builder);
        }
        //高亮------------------------------《


        //聚合------------------------------》


        TermsAggregationBuilder catalog_agg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(2);
        //三级分类名称子聚合
        catalog_agg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catelogName").size(1));
        sourceBuilder.aggregation(catalog_agg);

        TermsAggregationBuilder brand_agg = AggregationBuilders.terms("brand_agg").field("brandId").size(50);

        //brand_agg;
        //品牌子聚合名字和图片
        brand_agg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1));
        brand_agg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1));
        sourceBuilder.aggregation(brand_agg);

        NestedAggregationBuilder attr_agg = AggregationBuilders.nested("attr_agg" , "attrs");
        //聚合当前所有的attrId
        TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");
        //聚合当前attrId对应的名字
        attr_id_agg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));
        //聚合当前attrId对应的名字的值
        attr_id_agg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50));

        attr_agg.subAggregation(attr_id_agg);
        sourceBuilder.aggregation(attr_agg);
        //聚合------------------------------《

        System.out.println("DSL:"  + sourceBuilder.toString());
        SearchRequest request = new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX} , sourceBuilder);

        return request;
    }
}
